package com.sunday.common.core.remoting.rest.response.utils;

import com.sunday.common.core.enums.ErrorClassifyEnum;
import com.sunday.common.core.enums.ErrorCodeEnum;
import lombok.extern.slf4j.Slf4j;

import java.util.Optional;

/**
 * 错误码等级工具
 *
 * @author zsy
 * @since 2022/10/14
 */
@Slf4j
public class ErrorCodeLevelUtils {


    public static SwapRestCode swap(boolean success, String errorCode, String errorMessage) {
        return swap(success, errorCode, errorMessage, null);
    }

    public static SwapRestCode swap(boolean success, String errorCode, String errorMessage, ErrorCodeEnum swapCodeEnum) {
        return swap(success, errorCode, errorMessage, swapCodeEnum, false);
    }

    /**
     * 开启置换响应
     *
     * @param success      为true时封装直接返回结果
     * @param errorCode
     * @param errorMessage
     * @param swapCodeEnum
     * @param lowLevelSwap
     * @return {@link SwapRestCode}
     */
    public static SwapRestCode swap(boolean success, String errorCode, String errorMessage, ErrorCodeEnum swapCodeEnum, boolean lowLevelSwap) {
        assert errorCode != null : "errorCode must not be null";
        if (success) {
            return SwapRestCode.builder()
                    .errorCode(errorCode)
                    .errorMessage(errorMessage)
                    .build();
        } else {
            return errorSwap(errorCode, errorMessage, swapCodeEnum, lowLevelSwap);
        }
    }

    /**
     * 异常置换置换
     *
     * @param errorCode
     * @param errorMessage
     * @param swapCodeEnum 进行异常编码枚举置换, 当值不存在时采用屏蔽高等级异常
     * @param lowLevelSwap 低等级是否遵从置换
     * @return {@link SwapRestCode}
     */
    public static SwapRestCode errorSwap(String errorCode, String errorMessage, ErrorCodeEnum swapCodeEnum, boolean lowLevelSwap) {
        assert errorCode != null : "errorCode must not be null";
        return Optional.ofNullable(swapCodeEnum)
                .map(codeEnum -> {
                    // 是否来源用户等级错误(A级) 且 低等级遵从置换
                    if (isSourceUser(errorCode)) {
                        if (lowLevelSwap) {
                            SwapRestCode swapRestCode = SwapRestCode.builder().errorCode(codeEnum.errorCode).errorMessage(codeEnum.errorMessage).build();
                            log.info("[A][SWAP], response -> [{}:{}] -> {}", errorCode, errorMessage, swapRestCode);
                            return swapRestCode;
                        }
                        return SwapRestCode.builder().errorCode(errorCode).errorMessage(errorMessage).build();
                    } else {
                        SwapRestCode swapRestCode = SwapRestCode.builder().errorCode(codeEnum.errorCode).errorMessage(codeEnum.errorMessage).build();
                        log.info("[B/C][SWAP], response -> [{}:{}] -> {}", errorCode, errorMessage, swapRestCode);
                        return swapRestCode;
                    }
                })
                /**
                 * 这里需要特别说明为什么不是 orElse 而采用 orElseGet
                 * orElse(T)无论前面Optional容器是null还是non-null，都会执行orElse里的方法，orElseGet(Supplier)并不会，如果service无异常抛出的情况下，Optional使用orElse或者orElseGet的返回结果都是一样的
                 * Optional的orElse(T)若方法不是纯计算型的，有与数据库交互或者远程调用的，都应该使用orElseGet()
                 */
                .orElseGet(() -> maskHighLevelError(errorCode, errorMessage));
    }

    /**
     * 屏蔽高等级异常，高等级统一异常 B0_001
     *
     * @param errorCode    根据 errorCode 获取异常等级，A级以上高位屏蔽
     * @param errorMessage
     * @return {@link SwapRestCode}
     */
    public static SwapRestCode maskHighLevelError(String errorCode, String errorMessage) {
        assert errorCode != null : "errorCode must not be null";
        return Optional.ofNullable(errorCode)
                .filter(code -> isSourceUser(code))
                .map(code -> SwapRestCode.builder().errorCode(code).errorMessage(errorMessage).build())
                .orElseGet(() -> {
                    if (!errorCode.equals(ErrorCodeEnum.B0_001.errorCode)) {
                        SwapRestCode swapRestCode = SwapRestCode.builder().errorCode(ErrorCodeEnum.B0_001.errorCode).errorMessage(ErrorCodeEnum.B0_001.errorMessage).build();
                        log.info("[B/C][MASK], response -> [{}:{}] -> {}", errorCode, errorMessage, swapRestCode);
                        return swapRestCode;
                    }
                    return SwapRestCode.builder().errorCode(errorCode).errorMessage(errorMessage).build();
                });
    }

    /**
     * 是否来源用户等级错误(A级)
     *
     * @param errorCode
     * @return {@link boolean}
     */
    public static boolean isSourceUser(String errorCode) {
        return levelMatch(errorCode, ErrorClassifyEnum.A);
    }

    /**
     * 指定等级匹配
     *
     * @param errorCode
     * @param errorClassifyEnum
     * @return {@link boolean}
     */
    public static boolean levelMatch(String errorCode, ErrorClassifyEnum errorClassifyEnum) {
        assert errorCode != null : "errorCode must not be null";
        return Optional.ofNullable(errorCode)
                .filter(code -> errorClassifyEnum != null)
                .map(code -> code.startsWith(errorClassifyEnum.toString()))
                .orElse(false);
    }

}
